package com.tushare.controller;

import com.tushare.entity.*;
import com.tushare.service.*;
import com.tushare.util.CalendarUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@RestController
@CrossOrigin("*")
public class ScheduledController {
    private static final String API_URL = "http://192.168.2.12:8061/";
    private final HttpHeaders headers = new HttpHeaders();
    private final HttpEntity<Boolean> entity = new HttpEntity<>(headers);
    private final AtomicInteger atomicInteger = new AtomicInteger(-1);

    @Autowired
    IStockBasicService stockBasicService;
    @Autowired
    IStockCompanyService stockCompanyService;
    @Autowired
    IHsConstService hsConstService;
    @Autowired
    IConceptService conceptService;
    @Autowired
    IIncomeService incomeService;
    @Autowired
    IBalanceSheetService balanceSheetService;
    @Autowired
    ICashflowService cashflowService;
    @Autowired
    IForecastService forecastService;
    @Autowired
    IExpressService expressService;
    @Autowired
    IDividendService dividendService;
    @Autowired
    IFinaIndicatorService finaIndicatorService;
    @Autowired
    ITop10HoldersService top10HoldersService;
    @Autowired
    ITop10FloatHoldersService top10FloatHoldersService;
    @Autowired
    IConceptDetailService conceptDetailService;
    @Autowired
    IShareFloatService shareFloatService;
    @Autowired
    IStkHolderNumberService stkHolderNumberService;
    @Autowired
    IHighStockService highStockService;
    @Autowired
    IDailyBasicService dailyBasicService;
    @Autowired
    ILastBasicService lastBasicService;
    @Autowired
    IDailyService dailyService;
    @Autowired
    IHkHoldService hkHoldService;
    @Autowired
    IMarginService marginService;
    @Autowired
    IMarginDetailService marginDetailService;
    @Autowired
    ITimeShareChartService timeShareChartService;
    @Autowired
    RestTemplate restTemplate;
    @Resource(name = "testFxbDrawExecutor")
    ExecutorService asyncService;

    /**
     * 常规数据下载， 不需要每天更新
     */
    @GetMapping("/download_basic")
    public String downloadBasic() {
        if (atomicInteger.get() >= 0) {
            return "正在现在中，请稍后";
        }
        atomicInteger.set(0);
        // 股票列表
        if (stockBasicService.count() <= 0) {
            List<StockBasic> stockBasicList = restTemplate.exchange(API_URL + "stock_basic", HttpMethod.GET,
                    entity, new ParameterizedTypeReference<List<StockBasic>>() {
                    }).getBody();
            if (stockBasicList == null || stockBasicList.size() == 0) {
                atomicInteger.set(-1);
                return "股票列表下载失败";
            }
            stockBasicService.saveStockBasics(stockBasicList);
        }

        if (stockCompanyService.count() <= 0) {
            List<StockCompany> stockCompanyList = restTemplate.exchange(API_URL + "stock_company", HttpMethod.GET,
                    entity, new ParameterizedTypeReference<List<StockCompany>>() {
                    }).getBody();
            if (stockCompanyList == null || stockCompanyList.size() == 0) {
                atomicInteger.set(-1);
                return "上市公司基本信息下载失败";
            }
            stockCompanyService.saveStockCompanies(stockCompanyList);
        }

        if (hsConstService.count() <= 0) {
            List<HsConst> shConstList = restTemplate.exchange(API_URL + "hs_const?hs_type=SH", HttpMethod.GET,
                    entity, new ParameterizedTypeReference<List<HsConst>>() {
                    }).getBody();
            if (shConstList == null || shConstList.size() == 0) {
                atomicInteger.set(-1);
                return "沪股通成分股下载失败";
            }
            List<HsConst> szConstList = restTemplate.exchange(API_URL + "hs_const?hs_type=SZ", HttpMethod.GET,
                    entity, new ParameterizedTypeReference<List<HsConst>>() {
                    }).getBody();
            if (szConstList == null || szConstList.size() == 0) {
                atomicInteger.set(-1);
                return "深股通成分股下载失败";
            }
            hsConstService.saveHsConsts(shConstList);
            hsConstService.saveHsConsts(szConstList);
        }

        if (conceptService.count() <= 0) {
            List<Concept> conceptList = restTemplate.exchange(API_URL + "concept", HttpMethod.GET,
                    entity, new ParameterizedTypeReference<List<Concept>>() {
                    }).getBody();
            if (conceptList == null || conceptList.size() == 0) {
                atomicInteger.set(-1);
                return "概念股分类下载失败";
            }
            conceptService.saveConcepts(conceptList);
        }

        List<StockBasic> list = stockBasicService.getAllStockBasic();
        if (list.size() == 0) {
            atomicInteger.set(-1);
            return "数据库获取股票信息失败";
        }
        list.forEach(stockBasic -> asyncService.submit(() -> {
            try {
                downloadSingleBasic(stockBasic);
            } catch (RestClientException e) {
                System.out.println(stockBasic.getTs_code() + "\tRestClientException:");
            } catch (Exception e) {
                System.out.println(stockBasic.getTs_code() + "\tException:");
            }

            atomicInteger.incrementAndGet();
            if (atomicInteger.get() > 4300) {
                System.out.println("我已经下载的数据量是：" + atomicInteger.get() + "/" + list.size());
            }
            if (atomicInteger.get() == list.size()) {
                System.out.println("downloadBasic over");
                System.out.println("downloadBasic over");
                System.out.println("downloadBasic over");
                System.out.println("downloadBasic over");
                atomicInteger.set(-1);
            }
        }));
        return "";
    }

    @GetMapping("/download_daily")
    public boolean downloadDaily(@RequestParam(name = "start_date", defaultValue = "20190101") Integer start_date) {
        Daily daily = dailyService.getLastDaily();
        DailyBasic dailyBasic = dailyBasicService.getLastStockBasic();
        HkHold hkHold = hkHoldService.getLastHkHold();
        Margin margin = marginService.getLastMargin();
        MarginDetail marginDetail = marginDetailService.getLastMarginDetail();
        int dailyValue = daily == null ? start_date : daily.getTrade_date();
        int dailyBasicValue = dailyBasic == null ? start_date : dailyBasic.getTrade_date();
        int hkHoldValue = hkHold == null ? start_date : hkHold.getTrade_date();
        int marginValue = margin == null ? start_date : margin.getTrade_date();
        int marginDetailValue = marginDetail == null ? start_date : marginDetail.getTrade_date();
        start_date = Math.min(dailyValue, dailyBasicValue);
        start_date = Math.min(start_date, hkHoldValue);
        start_date = Math.min(start_date, marginValue);
        start_date = Math.min(start_date, marginDetailValue);
        String serveUrl = API_URL + "trade_cal?start_date=" + start_date + "&end_date=" + CalendarUtil.getCurrentDate();
        // 交易日期
        List<TradeCal> tradeCalList = restTemplate.exchange(serveUrl, HttpMethod.GET, entity,
                new ParameterizedTypeReference<List<TradeCal>>() {
                }).getBody();
        if (tradeCalList == null || tradeCalList.size() == 0) {
            return false;
        }
        tradeCalList.sort(Comparator.comparingInt(TradeCal::getCal_date));
        asyncService.submit(() -> tradeCalList.stream().filter(tradeCal -> tradeCal.getCal_date() > dailyValue)
                .forEach(tradeCal -> {
                    String dailyUrl = API_URL + "daily?trade_date=" + tradeCal.getCal_date();
                    List<Daily> dailyList = restTemplate.exchange(dailyUrl, HttpMethod.GET, entity,
                            new ParameterizedTypeReference<List<Daily>>() {
                            }).getBody();
                    if (dailyList != null && dailyList.size() > 0) {
                        dailyService.saveDailies(dailyList);
                    }
                }));
        asyncService.submit(() -> tradeCalList.stream().filter(tradeCal -> tradeCal.getCal_date() > dailyBasicValue)
                .forEach(tradeCal -> {
                    String dailyBasicUrl = API_URL + "daily_basic?trade_date=" + tradeCal.getCal_date();
                    List<DailyBasic> dailyBasicList = restTemplate.exchange(dailyBasicUrl, HttpMethod.GET, entity,
                            new ParameterizedTypeReference<List<DailyBasic>>() {
                            }).getBody();
                    if (dailyBasicList != null && dailyBasicList.size() > 0) {
                        dailyBasicService.saveDailyBasics(dailyBasicList);
                    }
                }));
        asyncService.submit(() -> tradeCalList.stream().filter(tradeCal -> tradeCal.getCal_date() > hkHoldValue)
                .forEach(tradeCal -> {
                    String hkHoldUrl = API_URL + "hk_hold?trade_date=" + tradeCal.getCal_date();
                    List<HkHold> hkHoldList = restTemplate.exchange(hkHoldUrl, HttpMethod.GET, entity,
                            new ParameterizedTypeReference<List<HkHold>>() {
                            }).getBody();
                    if (hkHoldList != null && hkHoldList.size() > 0) {
                        hkHoldService.saveOrUpdateBatch(hkHoldList);
                    }

                }));
        asyncService.submit(() -> tradeCalList.stream().filter(tradeCal -> tradeCal.getCal_date() > marginValue)
                .forEach(tradeCal -> {
                    String marginUrl = API_URL + "margin?trade_date=" + tradeCal.getCal_date();
                    List<Margin> marginList = restTemplate.exchange(marginUrl, HttpMethod.GET, entity,
                            new ParameterizedTypeReference<List<Margin>>() {
                            }).getBody();
                    if (marginList != null && marginList.size() > 0) {
                        marginService.saveOrUpdateBatch(marginList);
                    }

                }));
        asyncService.submit(() -> tradeCalList.stream().filter(tradeCal -> tradeCal.getCal_date() > marginDetailValue)
                .forEach(tradeCal -> {
                    String marginDetailUrl = API_URL + "margin_detail?trade_date=" + tradeCal.getCal_date();
                    List<MarginDetail> marginDetailList = restTemplate.exchange(marginDetailUrl, HttpMethod.GET, entity,
                            new ParameterizedTypeReference<List<MarginDetail>>() {
                            }).getBody();
                    if (marginDetailList != null && marginDetailList.size() > 0) {
                        marginDetailService.saveOrUpdateBatch(marginDetailList);
                    }

                }));
        return true;
    }

    @GetMapping("/download_time_share_chart")
    public boolean downloadTimeShareChart() {
        this.stockBasicService.getAllStockBasic().forEach(stockBasic -> {
            try {
                Thread.sleep(1000);
                String dailyUrl = API_URL + "timeShareChart?ts_code=" + stockBasic.getTs_code();
                List<TimeShareChart> timeShareChartList = restTemplate.exchange(dailyUrl, HttpMethod.GET, entity,
                        new ParameterizedTypeReference<List<TimeShareChart>>() {
                        }).getBody();
                if (timeShareChartList != null && timeShareChartList.size() > 0) {
                    timeShareChartService.deleteTimeShareChartByTsCode(stockBasic.getTs_code());
                    timeShareChartService.saveOrUpdateBatch(timeShareChartList);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        return true;
    }

    @GetMapping("/download_all_stk_holdernumber")
    public boolean downloadStkHolderNumber() {
        List<StockBasic> stockBasicList = stockBasicService.getAllStockBasic();
        long total = stockBasicList.size();
        AtomicInteger position = new AtomicInteger();
        stockBasicList.forEach(stockBasic -> {
            // 股东人数
            List<StkHolderNumber> stkHolderNumberList = restTemplate.exchange(API_URL + "stk_holdernumber?ts_code=" + stockBasic.getTs_code(),
                    HttpMethod.GET, entity, new ParameterizedTypeReference<List<StkHolderNumber>>() {
                    }).getBody();
            if (stkHolderNumberList != null && stkHolderNumberList.size() > 0) {
                stkHolderNumberList = stkHolderNumberList.stream().filter(stkHolderNumber -> stkHolderNumber.getHolder_num() > 0).collect(Collectors.toList());
                stkHolderNumberService.saveStkHolderNumbers(stkHolderNumberList);
            }
            try {
                System.out.println("股东人数：" + position.incrementAndGet() + "/" + total);
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        return true;
    }

    @GetMapping("/download_high_stock")
    public boolean downloadHighStock() {
        List<HighStock> highStockList = highStockService.getAllHighStock();
        long total = highStockList.size();
        AtomicInteger position = new AtomicInteger();
        highStockList.forEach(stockBasic -> {
            // 股东人数
            List<StkHolderNumber> stkHolderNumberList = restTemplate.exchange(API_URL + "stk_holdernumber?ts_code=" + stockBasic.getTs_code(),
                    HttpMethod.GET, entity, new ParameterizedTypeReference<List<StkHolderNumber>>() {
                    }).getBody();
            if (stkHolderNumberList != null && stkHolderNumberList.size() > 0) {
                stkHolderNumberList = stkHolderNumberList.stream().filter(stkHolderNumber -> stkHolderNumber.getHolder_num() > 0).collect(Collectors.toList());
                stkHolderNumberService.saveStkHolderNumbers(stkHolderNumberList);
            }
            try {
                System.out.println("股东人数：" + position.incrementAndGet() + "/" + total);
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        return true;
    }

    /**
     * 下载单只股票的信息
     */
    private void downloadSingleBasic(StockBasic stockBasic) throws RestClientException {
        System.out.println("downloadSingleBasic : " + stockBasic.getTs_code());
        // 利润表
        List<Income> incomeList = restTemplate.exchange(API_URL + "income?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<Income>>() {
                }).getBody();
        if (incomeList != null && incomeList.size() > 0) {
            incomeService.saveIncomes(incomeList);
        }
        // 资产负债表
        List<BalanceSheet> balanceSheetList = restTemplate.exchange(API_URL + "balanceSheet?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<BalanceSheet>>() {
                }).getBody();
        if (balanceSheetList != null && balanceSheetList.size() > 0) {
            balanceSheetService.saveBalanceSheets(balanceSheetList);
        }
        // 现金流量表
        List<Cashflow> cashflowList = restTemplate.exchange(API_URL + "cashFlow?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<Cashflow>>() {
                }).getBody();
        if (cashflowList != null && cashflowList.size() > 0) {
            cashflowService.saveCashflows(cashflowList);
        }
        // 业绩预告
        List<Forecast> forecastList = restTemplate.exchange(API_URL + "forecast?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<Forecast>>() {
                }).getBody();
        if (forecastList != null && forecastList.size() > 0) {
            forecastService.saveForecasts(forecastList);
        }
        // 业绩快报
        List<Express> expressList = restTemplate.exchange(API_URL + "express?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<Express>>() {
                }).getBody();
        if (expressList != null && expressList.size() > 0) {
            expressService.saveExpresses(expressList);
        }
        // 分红送股
        List<Dividend> dividendList = restTemplate.exchange(API_URL + "dividend?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<Dividend>>() {
                }).getBody();
        if (dividendList != null && dividendList.size() > 0) {
            dividendService.saveDividends(dividendList);
        }
        // 财务指标数据
        List<FinaIndicator> finaIndicatorList = restTemplate.exchange(API_URL + "fina_indicator?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<FinaIndicator>>() {
                }).getBody();
        if (finaIndicatorList != null && finaIndicatorList.size() > 0) {
            finaIndicatorService.saveFinaIndicators(finaIndicatorList);
        }
        // 前十大股东
        List<Top10Holders> top10HoldersList = restTemplate.exchange(API_URL + "top10_holders?ts_code=" + stockBasic.getTs_code()
                        + "&start_date=" + stockBasic.getList_date(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<Top10Holders>>() {
                }).getBody();
        if (top10HoldersList != null && top10HoldersList.size() > 0) {
            top10HoldersService.saveTop10Holders(top10HoldersList);
        }
        // 前十大流通股东
        List<Top10FloatHolders> top10FloatHoldersList = restTemplate.exchange(API_URL + "top10_floatholders?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<Top10FloatHolders>>() {
                }).getBody();
        if (top10FloatHoldersList != null && top10FloatHoldersList.size() > 0) {
            top10FloatHoldersService.saveTop10FloatHolders(top10FloatHoldersList);
        }
        // 概念股列表
        List<ConceptDetail> conceptDetailList = restTemplate.exchange(API_URL + "concept_detail?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<ConceptDetail>>() {
                }).getBody();
        if (conceptDetailList != null && conceptDetailList.size() > 0) {
            conceptDetailService.saveConceptDetails(conceptDetailList);
        }
        // 限售股解禁
        List<ShareFloat> shareFloatList = restTemplate.exchange(API_URL + "share_float?ts_code=" + stockBasic.getTs_code(),
                HttpMethod.GET, entity, new ParameterizedTypeReference<List<ShareFloat>>() {
                }).getBody();
        if (shareFloatList != null && shareFloatList.size() > 0) {
            shareFloatService.saveShareFloats(shareFloatList);
        }
    }

}
